在TV开发中RecycleView的使用是最让人头疼的经常会出现焦点丢失。因为当item未显示时不能获取焦点。所以当我们按上下键时经常丢失焦点或者焦点乱跳。要解决这个问题我们必须要手动控制RecyclerView 的按键和焦点移动。
所以我们这里需要需要自定义RecycleView。
代码如下,各个方法作用在注视中已添加:
public class TvRecyclerView extends RecyclerView
{
//正常跟随滚动
private static final int SCROLL_NORMAL = 0;
//居中滚动
private static final int SCROLL_FOLLOW = 1;
//滚动模式
private int scrollModel;
//当前选中的position
private int mSelectedPosition = 0;
//下一个聚焦的View
private View mNextFocused;
public TvRecyclerViewNew(Context context)
{
this(context, null);
}
public TvRecyclerViewNew(Context context, AttributeSet attrs)
{
this(context, attrs, -1);
}
public TvRecyclerViewNew(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
/**
* 初始化
*
* @param context
* @param attrs
* @param defStyle
*/
private void init(Context context, AttributeSet attrs, int defStyle)
{
initView();
initAttr(attrs);
}
/**
* 初始化View
* 为避免recycleview焦点混乱常用的一些设置
*/
private void initView()
{
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setHasFixedSize(true);
setWillNotDraw(true);
setOverScrollMode(View.OVER_SCROLL_NEVER);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
setClickable(false);
setFocusable(true);
setFocusableInTouchMode(true);
/**
防止RecyclerView刷新时焦点不错乱bug的步骤如下:
(1)adapter执行setHasStableIds(true)方法
(2)重写getItemId()方法,让每个view都有各自的id
(3)RecyclerView的动画必须去掉
*/
setItemAnimator(null);
}
/**
* 初始化样式
* 是否居中滚动
* @param attrs
*/
private void initAttr(AttributeSet attrs)
{
TypedArray typeArray = getContext().obtainStyledAttributes(attrs, R.styleable.TvRecyclerView);
scrollModel = typeArray.getInteger(R.styleable.TvRecyclerView_scrollMode, 0);
}
/**
* 恢复回收之前的状态
* @param state
*/
@Override
protected void onRestoreInstanceState(Parcelable state)
{
Bundle bundle = (Bundle) state;
Parcelable superData = bundle.getParcelable("super_data");
super.onRestoreInstanceState(superData);
setItemSelected(bundle.getInt("select_pos", 0));
}
/**
* 回收之前保存状态
* @return
*/
@Override
protected Parcelable onSaveInstanceState()
{
Bundle bundle = new Bundle();
Parcelable superData = super.onSaveInstanceState();
bundle.putParcelable("super_data", superData);
bundle.putInt("select_pos", mSelectedPosition);
return bundle;
}
/**
* 解决4.4版本抢焦点的问题
* @return
*/
@Override
public boolean isInTouchMode()
{
if (Build.VERSION.SDK_INT == 19)
{
return !(hasFocus() && !super.isInTouchMode());
} else
{
return super.isInTouchMode();
}
}
@Override
public void requestChildFocus(View child, View focused)
{
super.requestChildFocus(child, focused);
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate)
{
final int parentLeft = getPaddingLeft();
final int parentRight = getWidth() - getPaddingRight();
final int parentTop = getPaddingTop();
final int parentBottom = getHeight() - getPaddingBottom();
final int childLeft = child.getLeft() + rect.left;
final int childTop = child.getTop() + rect.top;
final int childRight = childLeft + rect.width();
final int childBottom = childTop + rect.height();
final int offScreenLeft = Math.min(0, childLeft - parentLeft);
final int offScreenRight = Math.max(0, childRight - parentRight);
final int offScreenTop = Math.min(0, childTop - parentTop);
final int offScreenBottom = Math.max(0, childBottom - parentBottom);
final boolean canScrollHorizontal = getLayoutManager().canScrollHorizontally();